﻿using System;
using log4net;
using System.IO;
using log4net.Core;
using log4net.Filter;
using log4net.Config;
using log4net.Appender;
using log4net.Repository;
using System.Diagnostics;
using System.Collections.Generic;

namespace UtilTools
{
    /// <summary>
    /// 系统日志
    /// </summary>
    public static class SysLog
    {
        /// <summary>
        /// 调试日志
        /// </summary>
        /// <param name="msg"></param>
        public static void Debug(object msg) { FileLogs.Debug(msg); }
        /// <summary>
        /// 调试日志
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="ex"></param>
        public static void Debug(object msg, Exception ex) { FileLogs.Debug(msg, ex); }
        /// <summary>
        /// 错误日志
        /// </summary>
        /// <param name="msg"></param>
        public static void Error(object msg) { FileLogs.Error(msg); }
        /// <summary>
        /// 错误日志
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="ex"></param>
        public static void Error(object msg, Exception ex) { FileLogs.Error(msg, ex); }
        /// <summary>
        /// 日志
        /// </summary>
        /// <param name="msg"></param>
        public static void Info(object msg) { FileLogs.Info(msg); }
        /// <summary>
        /// 日志
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="ex"></param>
        public static void Info(object msg, Exception ex) { FileLogs.Info(msg, ex); }
        /// <summary>
        /// 警告日志
        /// </summary>
        /// <param name="msg"></param>
        public static void Warn(object msg) { FileLogs.Warn(msg); }
        /// <summary>
        /// 警告日志
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="ex"></param>
        public static void Warn(object msg, Exception ex) { FileLogs.Warn(msg, ex); }
        const String fileLogFormat = "%n记录时间：%date %n日志级别：%-5level %n类及方法：%logger  %n描述：%message %newline";
        const String fileLogBlock = "%newline==================================== Log ====================================%newline";
        static readonly ILoggerRepository fileLogger = LogManager.CreateRepository("GcNetLogs");
        static Boolean fileLoggerActive;
        static ILog FileLogs
        {
            get
            {
                if (!fileLoggerActive) { FileLoggerConfigure(); }
                return LogManager.GetLogger(fileLogger.Name, GetMethodFullName());
            }
        }
        static void FileLoggerConfigure()
        {
            Dictionary<String, Level> levels = new Dictionary<string, Level>
            {
                { "debug", Level.Debug },
                { "warn", Level.Warn },
                { "info", Level.Info },
                { "error", Level.Error },
            };
            foreach (var item in levels)
            {
                BasicConfigurator.Configure(fileLogger, GetFileAppender(item.Value, item.Key));
            }
            fileLoggerActive = true;
        }
        static RollingFileAppender GetFileAppender(Level level, String pathName)
        {
            var layout = new log4net.Layout.PatternLayout(fileLogBlock + fileLogFormat);
            var fileappend = new RollingFileAppender
            {
                AppendToFile = true,
                ImmediateFlush = true,
                StaticLogFileName = false,
                MaxFileSize = 1024 * 1024 * 5,
                LockingModel = new FileAppender.MinimalLock(),
                RollingStyle = RollingFileAppender.RollingMode.Date,
                File = Path.Combine("logs", $"{pathName}{Path.DirectorySeparatorChar}"),
                DatePattern = $"yyyy-MM-dd'.log'",
                Name = $"{level.Name}RollingFileAppender",
                Layout = layout
            };
            LevelRangeFilter LevelRange = new LevelRangeFilter { LevelMax = level, LevelMin = level };
            LevelRange.ActivateOptions();
            fileappend.AddFilter(LevelRange);
            fileappend.ActivateOptions();
            return fileappend;
        }
        static string GetMethodFullName()
        {
            try
            {
                int depth = 3;
                StackTrace st = new StackTrace();
                int maxFrames = st.GetFrames().Length;
                StackFrame sf;
                string methodName, className;
                Type classType;
                do
                {
                    sf = st.GetFrame(depth++);
                    classType = sf.GetMethod().DeclaringType;
                    className = classType.ToString();
                } while (className.EndsWith("Exception", StringComparison.CurrentCulture) && depth < maxFrames);
                methodName = sf.GetMethod().Name;
                return className + "." + methodName;
            }
            catch (Exception ex)
            {
                if (!fileLoggerActive) { FileLoggerConfigure(); }
                LogManager.GetLogger(fileLogger.Name, $"{nameof(GetMethodFullName)}").Fatal(ex);
                return string.Empty;
            }
        }
    }
}
